﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Threading;

namespace ParallelRuntimeLibrary.Internal
{
    internal class ResourceManager
    {
        private uint mNextProcessor;
        private uint mPhysicalProcessorCount;

        private static object mLockObj = new object();

        private static ResourceManager mRM;

        internal uint PhysicalProcessorCount
        {
            get { return mPhysicalProcessorCount; }
        }

        /*///////////////////////////////////////////////////////////////////////////////////////////////*/

        #region Singleton Pattern

        public static ResourceManager RM
        {
            get
            {
                lock (mLockObj)
                {
                    if (mRM == null)
                        mRM = new ResourceManager();
                }
                return mRM;
            }
        }
        
        #endregion

        /*///////////////////////////////////////////////////////////////////////////////////////////////*/

        /// <summary>
        /// Resource Manager Constructor
        /// </summary>
        public ResourceManager()
        {
            this.mPhysicalProcessorCount = (uint)NativeMethod.GetProcessorCount();
            this.mNextProcessor = 0;
        }

        /// <summary>
        /// This function return a array of processor Id to assign to the worker threads.
        /// To make every worker thread work in different processor.
        /// </summary>
        public byte[] RequestHardwareThreads()
        {
            return RequestHardwareThreads(mPhysicalProcessorCount);
        }

        /// <summary>
        /// This function return a array of processor Id to assign to the worker threads.
        /// To make every worker thread work in different processor.
        /// </summary>
        public byte[] RequestHardwareThreads(uint requestCount)
        {
            if (requestCount <= 0)
                return null;
            //else if (requestCount > this.mPhysicalProcessorCount)
            //    requestCount = (ushort)this.mPhysicalProcessorCount;

            byte[] processorNumber = new byte[requestCount];
            
            for (int i = 0; i < requestCount; i++)
                processorNumber[i] = (byte)((this.mNextProcessor + i) % ((uint)this.mPhysicalProcessorCount));

            this.mNextProcessor = (this.mNextProcessor + (ushort)requestCount) % this.mPhysicalProcessorCount;

            return processorNumber;
        }
    }
}
